package com.sprouting.ops.handle;

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

/**
 * so-token拦截器
 * 拦截器：https://sa-token.cc/doc.html#/use/route-check
 * 过滤器：https://sa-token.cc/doc.html#/up/global-filter  适用于webFlux，网关。
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2023/3/18 21:49
 */
@Configuration
public class ResourcesAndSaTokenInterceptor implements WebMvcConfigurer {

    /**
     * 权限白名单(不做权限过滤)
     */
    @Value("#{'${ops.customize.auth.whites}'.split(',')}")
    private List<String> EXCLUDE_PATH_SWAGGER;


    /**
     * 注册 Sa-Token 拦截器，打开注解式鉴权功能。
     * 注意，只有注册了本拦截器才可以使用注解鉴权，常用的拦截器可以参考 {@link package-info} 。使用拦截器模式，只能在Controller层进行注解鉴权。
     * 如需在任意层级使用注解鉴权，请参考：AOP注解鉴权
     * @param registry 拦截器注册
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /// 注册 Sa-Token 拦截器，打开注解式鉴权功能 具体可以参考：https://sa-token.cc/doc.html#/use/route-check ，可以写非常复杂的匹配
        if (CollUtil.isEmpty(EXCLUDE_PATH_SWAGGER)){
            EXCLUDE_PATH_SWAGGER = new ArrayList<>();
        }

        registry.addInterceptor(new SaInterceptor(handle -> {
            // 参数一：要匹配的path路由。参数二：要执行的校验函数。
            SaRouter
                    .match("/**")
                    // 排除掉的 path 列表，可以写多个
                    .notMatch("/error","/favicon.ico")
                    .notMatch(EXCLUDE_PATH_SWAGGER)
                    // 排除掉 knife4j
                    .notMatch("/doc.html")
                    .check(r -> StpUtil.checkLogin());

            // 根据路由划分模块，不同模块不同鉴权。r 后面可以写任意代码
            // SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));

        }))
                // 哪里被参与匹配的，这里是全部，如果要指定前缀，可能就是 /bud/** 了
                .addPathPatterns("/**")
                // 放行的代码，上面不匹配还要加上下面这里，否则还是会被拦截
                .excludePathPatterns(EXCLUDE_PATH_SWAGGER);
    }

    // /**
    //  * 静态资源拦截处理，使得图片不需要经过nginx就可以直接查看
    //  * @param registry
    //  */
    // @Override
    // public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //     /*
    //         必须加"/"，不然映射不到
    //         registry.addResourceHandler("/asset/**") 匹配后，这个 asset 路径会被去掉
    //
    //         使用步骤
    //
    //             后端
    //             首先要在配置中将 release.url 配置 upload 的前缀不进行拦截，否则会被权限拦截器进行拦截，
    //
    //             前端
    //             然后前端请求要匹配资源路径
    //             涉及的参数，upload 前端的 setting.js 中的 resourceURL 要配置好，资源的前缀
    //             config/index.js 下的 proxyTable 代理设置中的拦截 asset， setting.resourceURL 配置
    //             访问：http://127.0.0.1:8084/ps/upload/asset/book/images/1565738077504323584.png
    //
    //         图片 访问地址：http://127.0.0.1:8084/upload/asset/1553764000786944000/notepad/images/1622282287736614912/1622282470587297792.png
    //         带后缀的 http://127.0.0.1:8091/ops/upload/asset/1831381431835279360/images/component/65968b9df86848aab4c1799e.png
    //
    //     */
    //
    //     /*
    //       注意，这里是前端的代理图片后的地址，只有开发模式下才有用，到了生产的时候，vue配置的这些代理都已经失效，此时，也就不会用到这个东西。也就是如果开发环境
    //         地址是 /upload/桶名(后端图片的前缀)/图片地址.png
    //         生产则是 /桶名(后端图片的前缀)/图片地址.png
    //      */
    //     // 开发模式匹配的路径
    //     registry.addResourceHandler(matchStaticResourcePath).addResourceLocations("file:/" + webPackagePath);
    //     // 生产模式匹配的路径，就少了前面的
    //     registry.addResourceHandler("/upload/asset/**").addResourceLocations("file:/" + StrUtil.removeSuffix(webPackagePath, "/") + ConstantPath.Base.BUCKET_PATH);
    //     // 前端打包后的存放地址，不要有中文路径，千万注意，最坑的是有时候中文可以，有时候忽然又不行了
    //     if (StrUtil.isNotEmpty(webPackagePath)){
    //         // 注意，这里最好不要直接给一个全部匹配，很容易出现被拦截404的问题，所有前端的访问带一个前缀即可
    //         registry.addResourceHandler("/**").addResourceLocations("file:/" + webPackagePath + "/");
    //     }
    // }
    //
    // /**
    //  * 统一对 controller 添加前缀,作用，主要解决，前端访问不想加前缀访问资源，后端因为同一拦截了，需要对controller的进行特殊处理，添加指定前缀访问
    //  * @param configurer
    //  */
    // @Override
    // public void configurePathMatch(PathMatchConfigurer configurer) {
    //     // 指定注解的方式，对有相关注解的必须要 前面这个参数才能访问，这里是 "/bud" 才可以访问。
    //     // configurer.addPathPrefix("/ops", c -> c.isAnnotationPresent(Controller.class) || c.isAnnotationPresent(RestController.class));
    //
    //
    //     // 指定包的方式，对指定的包添加前缀，必须要指定前缀才可以访问
    //     // configurer.addPathPrefix("/ops", c -> c.getPackage().getName().contains("com.sprouting.personal.controller"));
    // }

}
